package edu.bw.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * ServiceAdvice代表一个通知类,通知分很多类型
 * 前置通知: 在目标方法执行前执行(在目标方法执行之前插入的通知)
 * 后置通知: 目标方法正常执行并且返回后,执行后置通知,如果目标方法抛出异常,无法执行后置通知
 * 最终通知(类似finally代码块): 无论目标方法在执行过程是否出现异常,最终通知都会执行
 * 异常通知:目标方法抛出异常后执行的通知,如果目标方法没有抛出异常,不执行异常通知
 * <p>
 * 环绕通知(功能最强): 环绕通知可以实现以上四种通知,还能控制目标方法是否执行,以及获取目标方法的参数,返回值等
 */
@Component
public class ServiceAdvice {
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println(Arrays.toString(joinPoint.getArgs()) + " " + joinPoint.getSignature());
        System.out.println("前置通知");
    }

    public void afterReturningAdvice(JoinPoint joinPoint, Object retVal) {
        System.out.println(Arrays.toString(joinPoint.getArgs()) + " " + joinPoint.getSignature());
        System.out.println("获取到的返回值:" + retVal);
        System.out.println("后置通知");
    }

    public void finallyAdvice(JoinPoint joinPoint) {
        System.out.println("最终通知");
    }

    public void afterThrowingAdvice(JoinPoint joinPoint, Throwable throwable) {
        System.out.println("获取异常信息:" + throwable.getMessage());
        System.out.println("异常通知");
    }

    public void aroundAdvice(ProceedingJoinPoint pjp) {
        System.out.println(Arrays.toString(pjp.getArgs()) + " " + pjp.getSignature());
        //System.out.println("环绕通知");
        try {
            System.out.println("前置通知");
            Object retVal = pjp.proceed();//相当于执行目标方法,proceed()相当于执行目标方法,其返回值就是目标方法的返回值
            System.out.println("获取到返回值:" + retVal);
            System.out.println("后置通知");
        } catch (Throwable e) {
            System.out.println("异常通知");
            System.out.println("获取异常信息:" + e.getMessage());
            throw new RuntimeException(e);
        } finally {
            System.out.println("最终通知");
        }

    }
}


